<?php

namespace service;

use think\facade\Cache;
use think\facade\Config;
use think\Db;
use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException AS ClientException2;
use GuzzleHttp\Exception\ServerException as ServerException2;

/**
 * 短消息服务
 * Class SmsService
 * @package service
 */
class SmsService
{

    // 手机号码校验规则
    const CHECK_PHONE = '/^1[3-9]\d{9}$/';

    // 短信发送间隔
    const SMS_SEND_INTERVAL = 70;

    // 短信有效时间
    const EFFECTIVE_TIME = 600;

    // 发送限制次数
    const SENDING_LIMIT_COUNT = 5;

    // 解封次数时间（秒）
    const SEND_LIMIT_TIME = 900;

    // 限制缓存后缀
    const LIMIT_CACHE_SUFFIX = '_error_count';

    //配置 要跟type的键值对应上
    const SMS_OTHER = 0; //其他
    const SMS_LOGIN = 1; //登录
    const SMS_REGISTER = 2; //注册
    const SMS_VALIDATE = 3; //验证
    const SMS_APPLY_INVITE_CODE_SUCCESS = 4; //申请邀请码成功
    const SMS_APPLY_INVITE_CODE_FAIL = 5; //申请邀请码失败
    const SMS_TYPE = [
        0 => ['name' => '其他', 'color' => '#000000'],
        1 => ['name' => '登陆', 'color' => '#000000'],
        2 => ['name' => '注册', 'color' => '#000000'],
        3 => ['name' => '安全验证', 'color' => '#000000'],
        4 => ['name' => '申请邀请码成功', 'color' => '#000000'],
        5 => ['name' => '申请邀请码失败', 'color' => '#000000'],
    ];

    /**
     * 校验短信验证码
     * @param string $mobile
     * @param string $code
     * @return array
     */
    public static function verify($mobile = '', $code = '')
    {
        if (empty($mobile)) {
            return ['status' => false, 'msg' => '手机号码不能为空'];
        }

        if (!preg_match(self::CHECK_PHONE, $mobile)) {
            return ['status' => false, 'msg' => '手机号码不正确'];
        }

        // 配置是否验证

        if (Config::get('sms_pass') || in_array($mobile,Config::get('test_member_mobile_arr'))) {
            return ['status' => true, 'msg' => ''];
        }

        if (empty($code)) {
            return ['status' => false, 'msg' => '短信验证码不能为空'];
        }

        if (strlen($code) < 6) {
            return ['status' => false, 'msg' => '短信验证码必须是6位数字'];
        }

        if ($verify = Cache::get($mobile)) {
            $verify = json_decode($verify, true);
            if (!isset($verify['code']) || $verify['code'] != $code) {
                return ['status' => false, 'msg' => '短信验证码不正确'];
            }
            return ['status' => true, 'msg' => ''];
        }
        return ['status' => false, 'msg' => '请先获取短信验证码'];
    }

    /**
     * Function:发送短消息
     * @param $mobile
     * @param $type
     * @param null $other
     * @param $is_check  是否验证发送间隔已经发送缓存
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public static function send($mobile, $type, $other = null, $is_check = false)
    {


        if (empty($mobile) || !is_integer($type)) {
            return ['status' => false, 'msg' => '手机号和类型不能为空'];
        }
        $config_platform = Config::get('sms_platform');
        $platform = sysConfig('sms_platform');
        if (empty($platform)) $platform = $config_platform[0]['value'];
        $timestamp = time();
        if (!preg_match(self::CHECK_PHONE, $mobile)) {
            return ['status' => false, 'msg' => '手机号码不正确'];
        }
        $smsConfig = [
            'key' => sysConfig('sms_key'),
            'secret' => sysConfig('sms_secret'),
            'sign' => sysConfig('sms_sign'),
            'log' => [
                'phone_number' => $mobile,
                'type' => $type,
                'send_msg' => '',
                'res_msg' => '',
                'platform' => $platform,
                'create_time' => $timestamp
            ]
        ];
        if (empty($smsConfig['key']) || empty($smsConfig['secret']) || ($platform == $config_platform[0]['value'] && empty($smsConfig['sign']))) {
            return ['status' => false, 'msg' => '短信配置参数缺失'];
        }
        $template = Db::name('sms_template')->where(['platform' => $platform, 'type' => $type])->find();
        if (empty($template)) {
            return ['status' => false, 'msg' => '模板不存在或未配置'];
        }

        if (!$is_check) {
            if ($check = Cache::get($mobile, [])) {
                $check = json_decode($check, true);
                if (($timestamp - $check['timestamp']) < self::SMS_SEND_INTERVAL) {
                    return ['status' => false, 'msg' => '短信发送间隔过短'];
                }
            }

            // 发送限制缓存
            if ($errCache = Cache::get($mobile . self::LIMIT_CACHE_SUFFIX, [])) {
                if (($timestamp - $errCache['timestamp']) > (self::SEND_LIMIT_TIME - 1)) {
                    $errCache['timestamp'] = $timestamp;
                    $errCache['errCount']--;
                    Cache::set($mobile . self::LIMIT_CACHE_SUFFIX, $errCache);
                }

                if ($errCache['errCount'] >= self::SENDING_LIMIT_COUNT) {
                    return ['status' => false, 'msg' => sprintf('短信发送过于频繁，请%s分钟后再试', floor(self::SEND_LIMIT_TIME / 60))];
                }
            }
            $smsConfig['errCache'] = $errCache;
        }


        // 获取用户昵称
        $nickname = model('common/member/Member')->getVal('nickname', ['username' => $mobile]);
        $tempParam = array(
            '[date]' => date('Y-m-d H:i:s'),
            '[time]' => date('H:i:s'),
            '[nickname]' => empty($nickname) ? '用户' : $nickname,
            '[captcha]' => randStr()
        );

        $count = 0;
        if (!is_null($other)) {
            $other = is_array($other) ? $other : [$other];
            $count = count($other);
        }


        for ($i = 1; $i < $count + 1; $i++) $tempParam["[other_{$i}]"] = $other[$i - 1];

        $TemplateParam = str_replace(array_keys($tempParam), array_values($tempParam), $template['template_value']);

        return self::$platform($smsConfig, $mobile, $template['template_id'], $TemplateParam, $tempParam, $is_check);
    }

    private static function sendAliDy($smsConfig, $mobile, $templateId, $templateParam, $tempParam, $is_check)
    {
        AlibabaCloud::accessKeyClient($smsConfig['key'], $smsConfig['secret'])
            ->regionId('cn-hangzhou')
            ->asDefaultClient();
        try {
            $result = AlibabaCloud::rpc()
                ->product('Dysmsapi')
                ->version('2017-05-25')
                ->action('SendSms')
                ->method('POST')
                ->host('dysmsapi.aliyuncs.com')
                ->options([
                    'query' => [
                        'RegionId' => 'cn-hangzhou',
                        // 接收手机号
                        'PhoneNumbers' => $mobile,
                        // 必填项 签名(需要在阿里云短信服务后台申请)
                        'SignName' => $smsConfig['sign'],
                        // 必填项 短信模板code (需要在阿里云短信服务后台申请)
                        'TemplateCode' => $templateId,
                        //如果在短信中添加了${code} 变量则此项必填 要求为JSON格式
                        'TemplateParam' => $templateParam
                    ]
                ])->request();
            $res = $result->toArray();
            if ($res['Code'] == 'OK') {
                if (!$is_check) {
                    $errCache = $smsConfig['errCache'];
                    // 发送限制缓存
                    $errCache['errCount'] = ($errCache ? $errCache['errCount'] + 1 : 1);
                    $errCache['timestamp'] = $smsConfig['log']['create_time'];
                    Cache::set($mobile . self::LIMIT_CACHE_SUFFIX, $errCache);
                    Cache::set($mobile, json_encode(['code' => $tempParam['[captcha]'], 'timestamp' => $smsConfig['log']['create_time']]), self::EFFECTIVE_TIME);
                }
                $smsConfig['log']['res_msg'] = '发送成功';
            } else {
                $smsConfig['log']['res_msg'] = $res['Message'];
            }
            $smsConfig['log']['send_msg'] = $templateParam;
            self::_log($smsConfig['log']);
            if ($res['Code'] !== 'OK') {
                return ['status' => false, 'msg' => $smsConfig['log']['res_msg']];
            }
            return ['status' => true, 'msg' => $smsConfig['log']['res_msg']];
        } catch (ClientException $e) {
            $smsConfig['log']['res_msg'] = $e->getErrorMessage();
            self::_log($smsConfig['log']);

        } catch (ServerException $e) {
            $smsConfig['log']['res_msg'] = $e->getErrorMessage();
            self::_log($smsConfig['log']);
        }
        return ['status' => false, 'msg' => $smsConfig['log']['res_msg']];
    }

    private static function sendHuYi($smsConfig, $mobile, $templateId, $templateParam, $tempParam, $is_check)
    {
        $params = [
            'timeout' => 15,
            'connect_timeout' => 15,
            'form_params' => [
                'account' => $smsConfig['key'],
                'password' => $smsConfig['secret'],
                'mobile' => $mobile,
                'content' => $templateParam,
                'format' => 'json'
            ]
        ];
        try {
            $client = new Client();
            $response = $client->request('POST', 'http://106.ihuyi.com/webservice/sms.php?method=Submit', $params);
            $res = $response->getBody()->getContents();
            $res = json_decode($res, true);
            $smsConfig['log']['send_msg'] = $templateParam;
            if ($res['code'] == 2 && $res['msg'] == '提交成功') {
                if (!$is_check) {
                    $errCache = $smsConfig['errCache'];
                    // 发送限制缓存
                    $errCache['errCount'] = ($errCache ? $errCache['errCount'] + 1 : 1);
                    $errCache['timestamp'] = $smsConfig['log']['create_time'];
                    Cache::set($mobile . self::LIMIT_CACHE_SUFFIX, $errCache);
                    Cache::set($mobile, json_encode(['code' => $tempParam['[captcha]'], 'timestamp' => $smsConfig['log']['create_time']]), self::EFFECTIVE_TIME);
                }
                $smsConfig['log']['res_msg'] = '发送成功';
                self::_log($smsConfig['log']);
                return ['status' => true, 'msg' => '发送成功'];
            }
            if ($res['code'] == 4030 && $res['msg'] == 'BLACK-Y') {
                return ['status' => false, 'msg' => '手机号格式不正确'];
            }
            $smsConfig['log']['res_msg'] = $res['msg'];
            self::_log($smsConfig['log']);
            return ['status' => false, 'msg' => $res['msg']];
        } catch (ServerException2 $e) {
            $smsConfig['log']['res_msg'] = $e->getMessage();
            self::_log($smsConfig['log']);
        } catch (ClientException2 $e) {
            $smsConfig['log']['res_msg'] = $e->getMessage();
            self::_log($smsConfig['log']);
        }
        return ['status' => false, 'msg' => $smsConfig['log']['res_msg']];
    }

    private static function _log($data)
    {
        Db::name('sms_log')->insert($data);
    }
}
